package com.bangcommunity.bbframe.mlog.collector;

import com.bangcommunity.bbframe.common.base.attribute.AttributeHelper;
import com.bangcommunity.bbframe.mlog.LogContext;
import com.bangcommunity.bbframe.mlog.logger.LogFacilityFacade;
import com.bangcommunity.bbframe.mlog.logger.MLoggerName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author tanghc
 * @date 18/1/30
 */
public class StatisticCollector {
    static Logger logger = LoggerFactory.getLogger(StatisticCollector.class);

    private final static ConcurrentMap<String, AtomicReference<StatisticBean>> statisticsMap = new ConcurrentHashMap<>();

    public static void collect(String mkey, StatisticBaseBean changes) {

        AtomicReference<StatisticBean> reference = getReferenceInitIfNull(mkey);
        CollectorHelper.updateRefrence(reference, new StatisticBean(mkey), (current, update) -> {
            if (current == null) {
                update.collectFirst(changes);
            } else {
                update.collect(current, changes);
            }
        });
    }

    private static AtomicReference<StatisticBean> getReferenceInitIfNull(String mkey) {
        AtomicReference<StatisticBean> reference = statisticsMap.get(mkey);
        if (reference == null) {
            statisticsMap.putIfAbsent(mkey, new AtomicReference<>());
            reference = statisticsMap.get(mkey);
        }
        return reference;
    }

    public static void collect(String mkey, LogContext logContext, StatisticStateEnum stateEnum, Object result,
            Throwable throwable) {

        if (null != logContext) {
            StatisticBaseBean changes = new StatisticBaseBean(mkey);
            switch (stateEnum) {
            case succ:
                changes.setSucc(1);
                break;
            case fail:
                changes.setFail(1);
                break;
            case exception:
                changes.setException(1);
                break;
            }
            changes.setElapsedMs(logContext.getStopTimeMs() - logContext.getStartTimeMs());
            changes.setConcurrent(logContext.getConcurrent());
            collect(mkey, changes);
        }
    }

    public static void report() {
        logger.debug("report statistic");
        for (ConcurrentMap.Entry<String, AtomicReference<StatisticBean>> entry : statisticsMap.entrySet()) {
            String mkey = entry.getKey();
            logger.debug("report key:" + mkey);
            Logger statisticLogger = LogFacilityFacade.createLogger(MLoggerName.mlog_stat, mkey);
            AtomicReference<StatisticBean> value = entry.getValue();
            StatisticBean statisticBean = new StatisticBean(mkey);
            StatisticBean refrenceOldValue = CollectorHelper.updateRefrence(value, statisticBean, (current, update) -> {
                statisticBean.initStatistisFromStartVm(current);
            });
            // if (null != statisticLogger && null != refrenceOldValue &&
            // refrenceOldValue.getTransactions() > 0) {
            if (null != statisticLogger && null != refrenceOldValue) {
                String jsonString = AttributeHelper.convertToJsonString(refrenceOldValue.toAttributeAssemble());
                logger.debug("{},{}", statisticLogger.getName(), jsonString);
                statisticLogger.info("{}", jsonString);
            }

        }
    }
}
